package com.platform.modules.mall.service.impl;

import cn.hutool.core.util.RandomUtil;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.baomidou.mybatisplus.extension.toolkit.SqlHelper;
import com.platform.common.exception.BusinessException;
import com.platform.common.utils.*;
import com.platform.modules.mall.dao.MallPrizeDao;
import com.platform.modules.mall.entity.*;
import com.platform.modules.mall.service.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 奖品表Service实现类
 *
 * @author
 * @date 2021-05-26 08:39:03
 */
@Service("mallPrizeService")
public class MallPrizeServiceImpl extends ServiceImpl<MallPrizeDao, MallPrizeEntity> implements MallPrizeService {

    @Resource
    JedisUtil jedisUtil;
    @Resource
    private MallCardSnService cardSnService;
    @Resource
    private MallWinPrizeService winPrizeService;
    @Autowired
    private MallGoodsService goodsService;

    /**
     * 设置谢谢参与
     *
     * @param startIndex 开始位置
     * @param endIndex   结束位置 +1
     * @param list       奖品列表
     */
    private void pushPrizeEntity(int startIndex, int endIndex, List<MallPrizeEntity> list) {
        for (int j = startIndex; j < endIndex; j++) {
            MallPrizeEntity entity = new MallPrizeEntity();
            entity.setPrizeName("谢谢参与");
            entity.setType(-1);
            entity.setSort(j);
            entity.setImage("https://lybank-1302786294.cos.ap-guangzhou.myqcloud.com/images/20210914/3f002d97b0a6425983e58248aaa06aa0.png");
            list.add(j - 1, entity);
        }
    }

    @Override
    public MallPrizeEntity runLottery(MallUserEntity userEntity, String categoryId, Integer level) {
        MallPrizeEntity win = null;
        //随机开奖
        double ran1 = Math.random() * 100;
        //排序中奖概率从小到大排序
        List<MallPrizeEntity> entityList = this.list(new LambdaQueryWrapper<MallPrizeEntity>()
                .eq(MallPrizeEntity::getCategoryId, categoryId)
                .eq(MallPrizeEntity::getLevel, level)
                .ge(MallPrizeEntity::getProbability, ran1)
                .orderByAsc(MallPrizeEntity::getProbability));
        if (!entityList.isEmpty()) {
            for (MallPrizeEntity entity : entityList) {
                if (entity.getNumber() > 0) {
                    //判断库存是否满足 并且减少库存 （利用inndb的行锁实现串行修改）
                    if (this.PrizeNumberSubtract(entity.getPrizeId())) {
                        MallGoodsEntity goods = goodsService.getById(win.getCommodityId());
                        goodsService.minusGoodsNumber(goods, 1);
                        win = entity;
                        break;
                    }
                } else {
                    break;
                }
            }
        }
        //中奖标识
        boolean tag = false;
        if (win != null) {
            // 中奖发放卡券
            tag = cardSnService.sendCard(win.getCommodityId(), 1, userEntity);
        }
        if (tag) {
            // 查询中奖商品的图片
            MallGoodsEntity goodsEntity = goodsService.lambdaQuery().select(MallGoodsEntity::getListPicUrl).eq(MallGoodsEntity::getId, win.getCommodityId()).one();
            win.setImage(goodsEntity.getListPicUrl());
        } else {
            //未中奖
            win = this.getLosingPrize(categoryId);
        }
        //抽奖记录写入数据库
        winPrizeService.setWinPrize(userEntity, win,tag);
        return win;
    }

    @Override
    public MallPrizeEntity getLosingPrize(String categoryId) {
        List<JSONObject> entitys = jedisUtil.getCache(Constant.LOTTERY_LOSING_LIST, () -> {
            List<JSONObject> list = jedisUtil.getCache(Constant.LOTTERY_LIST, () -> getPrizeList(categoryId), List.class);
            return list.stream().filter(x -> x.getInteger("type") == -1).collect(Collectors.toList());
        }, List.class);
        if (entitys.isEmpty()) {
            throw new BusinessException("系统繁忙，请稍后再试！");
        }
        return entitys.get(RandomUtil.randomInt(0, entitys.size())).toJavaObject(MallPrizeEntity.class);
    }

    @Override
    public List<MallPrizeEntity> getPrizeList(String categoryId) {
        //通过组别获取卡卷列表 排序根据卡券排序从小到大
        List<MallPrizeEntity> list = this.list(new LambdaQueryWrapper<MallPrizeEntity>()
                .select(MallPrizeEntity::getSort, MallPrizeEntity::getPrizeName, MallPrizeEntity::getImage, MallPrizeEntity::getType)
                .eq(MallPrizeEntity::getCategoryId, categoryId)
                .orderByAsc(MallPrizeEntity::getSort)
                .last("limit 0,8"));
        if (list.size() < 8) {
            // 奖品不足使用 谢谢惠顾补上
            int temp;
            for (int i = 1; i <= list.size(); i++) {
                temp = list.get(i - 1).getSort();
                // 补充谢谢惠顾
                if (i != temp) {
                    pushPrizeEntity(i, temp, list);
                    i = temp;
                }
            }
            if (list.size() < 8) {
                pushPrizeEntity(list.size() + 1, 9, list);
            }
        }
        list = list.stream().sorted(Comparator.comparing(MallPrizeEntity::getSort)).collect(Collectors.toList());
        return list;
    }

    @Override
    public boolean PrizeNumberSubtract(String id) {
        return baseMapper.PrizeNumberSubtract(id) > 0;
    }

    @Override
    public List<MallPrizeEntity> queryAll(Map<String, Object> params) {
        return baseMapper.queryAll(params);
    }

    @Override
    public Page queryPage(Map<String, Object> params) {
        //排序
        params.put("sidx", "T.SORT");
        params.put("asc", true);
        Page<MallPrizeEntity> page = new Query<MallPrizeEntity>(params).getPage();
        return page.setRecords(baseMapper.selectMallPrizePage(page, params));
    }

    /**
     * 交换排序号
     *
     * @param entity
     */
    @Transactional(rollbackFor = Exception.class)
    void changeSort(MallPrizeEntity entity) {
        this.lambdaUpdate().set(MallPrizeEntity::getSort,
                        this.lambdaQuery().select(MallPrizeEntity::getSort).eq(MallPrizeEntity::getPrizeId, entity.getPrizeId()).one().getSort()
                ).eq(MallPrizeEntity::getSort, entity.getSort())
                .eq(MallPrizeEntity::getCategoryId, entity.getCategoryId())
                .update();
        this.lambdaUpdate().set(MallPrizeEntity::getSort, entity.getSort()).eq(MallPrizeEntity::getPrizeId, entity.getPrizeId());
    }

    /**
     * 奖品数据发送变更删除缓存
     */
    void dataChange() {
        jedisUtil.del(Constant.LOTTERY_LIST);
        jedisUtil.del(Constant.LOTTERY_LOSING_LIST);
    }

    /**
     * 实体验证
     *
     * @param entity 实体
     * @param type   变更类型 1add  2update
     */
    void entityVerify(MallPrizeEntity entity, int type) {
        if (entity.getCategoryId().equals("9")) {
            if (type == 1) {
                // 限制九宫格奖品个数
                if (this.lambdaQuery().eq(MallPrizeEntity::getCategoryId, entity.getCategoryId()).count() >= 8) {
                    throw new BusinessException("九宫格奖品只能设置 8 个");
                }
            }
            // 限制九宫格的排序号
            if (this.lambdaQuery()
                    .select(MallPrizeEntity::getPrizeId)
                    .eq(MallPrizeEntity::getSort, entity.getSort())
                    .eq(MallPrizeEntity::getCategoryId, entity.getCategoryId()).count() > 0) {
                if (type == 2) {
                    changeSort(entity);
                    return;
                }
                throw new BusinessException(String.format("九宫格%s号位置已被占用", entity.getSort()));
            }
        }
    }

    @Override
    public boolean add(MallPrizeEntity mallPrize) {
        entityVerify(mallPrize, 1);
        boolean result = this.save(mallPrize);
        dataChange();
        return result;
    }

    @Override
    public boolean update(MallPrizeEntity mallPrize) {
        entityVerify(mallPrize, 2);
        boolean result = this.updateById(mallPrize);
        dataChange();
        return result;
    }

    @Override
    public boolean delete(String prizeId) {
        return this.removeById(prizeId);
    }

    @Override
    public boolean deleteBatch(String[] prizeIds) {
        return SqlHelper.retBool(baseMapper.deleteBatchIds(Arrays.asList(prizeIds)));
    }

}
